package org.wz.complex.work.kit.code;


import cn.hutool.core.io.FileUtil;
import cn.hutool.core.util.StrUtil;
import com.zaxxer.hikari.HikariDataSource;
import org.wz.complex.work.bean.ColumnsMetadata;
import org.wz.complex.work.entity.auth.sysinfo.SysinfoMicro;
import org.wz.complex.work.entity.project.code.CodeJava;

import org.wz.complex.work.entity.project.database.DatabaseName;
import org.wz.complex.work.entity.project.database.DatabaseSource;
import org.wz.complex.work.entity.project.generator.GeneratorJava;

import org.wz.complex.work.kit.db.MetaKit;
import org.wz.complex.work.kit.str.StrKit;

import java.io.File;
import java.sql.Connection;
import java.util.ArrayList;
import java.util.List;
import java.util.concurrent.locks.ReentrantLock;
import java.util.stream.Stream;


public interface GeneratorJavaKit {

   public static void generate(GeneratorJava gen) throws Exception {
       // 代码类型
       String codeType = gen.getCodeType();
       if (StrKit.notNull(codeType)) {
           String[] types = codeType.split(",");
           Stream.of(types).forEach(type -> {
               new Thread(() -> genType(gen, type)).start();
           });
       }

   }

       static  void  genType(GeneratorJava gen, String type) {
            ReentrantLock lock = new ReentrantLock();
            try {
                lock.lock();

                //
                CodeJava project = gen.getCodeJava();
                SysinfoMicro service = gen.getSysinfoMicro();

                // 代码类型
                genTemplate(type, gen, project, service);
            } finally {
                lock.unlock();
            }
        }

    static void genTemplate(String type, GeneratorJava gen, CodeJava project, SysinfoMicro service) {
        String templatePath = project.getTemplatePath();
        String content = FileUtil.readUtf8String(templatePath + File.separator + type + ".java");
        // 替换内容
        content = handleContent(content, gen, project, service);
        if (type.equals("Entity")) {
            // 数据库字段
            DatabaseName dn = project.getDatabaseName();
            content = findFromDatabase(content, dn.getName(), gen.getTableName(), dn.getDatabaseSource());
        }
        // path
        String codePath = getCodePath(project);
        //
        codePath += File.separator + type.toLowerCase() + File.separator
                + service.getRoute() + File.separator
                + gen.getModule() + File.separator
                + gen.getJavaEntity() + ("Entity".equals(type) ? "" : type) + ".java";

        // write
        FileUtil.writeUtf8String(content, codePath);
    }


    static String findFromDatabase(String content, String dbName, String tableName, DatabaseSource source) {
        // 替换内容
        String last = content;
        String category = source.getCategory().trim().toLowerCase();
        List<ColumnsMetadata> metaList = new ArrayList<>();
        switch (category) {
            case "mysql": metaList = handleMysql(dbName, tableName, source); break;
        }
        last = last.replaceAll("__wz_dbColumns_wz__", handleMetaList(category, metaList))
        ;
        return last;
    }

    static String handleMetaList(String category, List<ColumnsMetadata> metaList) {
        try {
            StringBuilder sb = new StringBuilder();

            metaList.stream().filter(m -> !m.getColumnColumnName().toLowerCase().equals("id"))
                    .forEach( meta -> {

                        String fieldType = "String";
                        switch (category) {
                            case "mysql": fieldType = getMysqlFieldType(meta.getColumnTypeName().toUpperCase());break;
                            case "postgresql": fieldType = getPostgresFieldType(meta.getColumnTypeName().toUpperCase());break;
                        }

                        String[] tags = meta.getColumnRemarks().trim().split(",");

                        sb
                            .append("\t/**\n")
                            .append("\t * ")
                            .append(tags[0].trim())
                            .append("\n")
                            .append("\t */\n");
//                            .append("\t@TableField(\"" + meta.getColumnColumnName() + "\")\n");

                        String columnNullable = meta.getColumnNullable();
                        if ("n".equals(columnNullable)) {
                            sb.append("\t@NotBlank(message = \""+ meta.getColumnRemarks() +"不能为空\")\n");
                        }

                        sb.append("\tprivate ")
                                .append(fieldType)
                                .append(" ")
                                .append(StrUtil.toCamelCase(meta.getColumnColumnName()))
                                .append(";\n\n");

                        // complex
                        if (tags.length > 1) {
                            String tmp = StrUtil.toCamelCase(meta.getColumnColumnName());
                            String complex = tags[1].trim();
                            sb.append("\t@ComposeEntity\n");
                            sb.append("\t@TableField(exist = false) \n");
                            sb.append("\tprivate ")
                                    .append(StrUtil.upperFirst(tmp.substring(0, tmp.length() - 2)))
                                    .append(" ")
                                    .append(tmp.substring(0, tmp.length() - 2))
                                    .append(";  // " + complex + "   \n\n");
                        }

                    });

            return sb.toString();

        } catch (Exception ex){
            ex.printStackTrace();
            throw new RuntimeException("程序异常！");
        }
    }

    static String getPostgresFieldType(String columnTypeName) {
        switch (columnTypeName) {
            case "VARCHAR", "CHAR", "TEXT": return "String";
            case "INT8": return "Long";
            case "INT", "INT2", "INT4": return "Integer";
            case "FLOAT8": return "Double";
            case "FLOAT4": return "Float";
            case "Bool": return "Boolean";
            case  "TIMESTAMP", "DATE", "TIME", "DATETIME": return "Date";
            default: return "String";
        }
    }

    static String getMysqlFieldType(String columnTypeName) {
        switch (columnTypeName) {
            case "VARCHAR", "CHAR": return "String";
            case "BIGINT": return "Long";
            case "INT": return "Integer";
            case "DATE", "DATETIME", "TIMESTAMP": return "Date";
            default: return "String";
        }
    }

    static List<ColumnsMetadata>  handleMysql(String dbName, String tableName, DatabaseSource source) {

        List<ColumnsMetadata> list = new ArrayList<>();

        String jdbcUrl = "jdbc:mysql://" + source.getIpHost() + ":" + source.getPort() + "/" + dbName + "?useUnicode=true&characterEncoding=utf-8&serverTimezone=Asia/Shanghai&useSSL=false&allowPublicKeyRetrieval=true";
        String username = source.getUser();
        String password = source.getPassword();

        // 创建DataSource
        HikariDataSource dataSource = new HikariDataSource();
        dataSource.setJdbcUrl(jdbcUrl);
        dataSource.setUsername(username);
        dataSource.setPassword(password);
        dataSource.setDriverClassName("com.mysql.cj.jdbc.Driver"); // 注意：在某些情况下，你可能不需要显式设置驱动类名，因为HikariCP会自动加载驱动。但最好还是显式设置以避免潜在问题。

        try (Connection connection = dataSource.getConnection()) {
            //
            list = MetaKit.getColumns(connection, tableName);
        } catch (Exception e) {
            throw new RuntimeException(e);
        }
        return list;
    }

    static String getCodePath(CodeJava project) {
            return  project.getProjectPath() + File.separator
                    + "src/main/java"+ File.separator
                    + project.getPackageInfo()
                    .replaceAll("\\.", "/");
        }


    static String handleContent(String content, GeneratorJava gen, CodeJava project, SysinfoMicro service) {
            String last = content;
            //
            last = last.replaceAll("__wz_javaEntity_wz__", gen.getJavaEntity())
                    .replaceAll("__wz_packageInfo_wz__", project.getPackageInfo())
                    .replaceAll("__wz_microRoute_wz__", service.getRoute())
                    .replaceAll("__wz_javaModule_wz__", gen.getModule())
                    .replaceAll("__wz_dbTable_wz__", gen.getTableName())
                   .replaceAll("__wz_apiUrl_wz__", gen.getUrl())
            ;
            //
            return last;
        }





}
